package rctgl;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.Point;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.util.Properties;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JFileChooser;

import panoramic.IRenderable;
import panoramic.textures.TextureManager;
import panoramic.geometry.PanoVertex2;

import com.sun.opengl.util.texture.*;

import rctgl.park.RCTGLTextures;
import rctgl.park.sv4.SV4Park;
import rctgl.util.RLEDecoder;


public class RCTGLRenderer implements GLEventListener, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener
{
	private RCTGLViewer m_viewer = new RCTGLViewer();
    
    private GLU m_glu = new GLU();
    
    private IRenderable m_renderObject;
    
    private PanoVertex2 m_lastMouseCoords = null;
    
    public static SV4Park selectParkFromDisk() throws Exception
    {
    	Properties props = new Properties();
		
		String lastPath = null;
		
		try
		{
			props.load( new FileInputStream("rctgl.properties"));
			lastPath = props.getProperty("lastPath");
		}
		catch(Exception e)
		{
			
		}
		
		
		JFileChooser fc = new JFileChooser();
		
		if(lastPath != null)
		{
			fc.setCurrentDirectory( new File(lastPath) );
		}
		
		int returnVal = fc.showOpenDialog(null);
		
		if(returnVal != JFileChooser.APPROVE_OPTION)
			return null;
		
		props.setProperty("lastPath", fc.getCurrentDirectory().getAbsolutePath() );
		props.save( new FileOutputStream("rctgl.properties"), "");
		
		System.out.println( fc.getSelectedFile().getAbsolutePath() );
		
		
		RandomAccessFile f = new RandomAccessFile( fc.getSelectedFile().getAbsolutePath(), "r");
		
		byte [] originalData = new byte [ (int)f.length() ];
		
		f.readFully(originalData);
		
		f.close();
		
		ByteArrayInputStream bais = new ByteArrayInputStream( RLEDecoder.decodeRLE(originalData) );
		
		SV4Park testPark = new SV4Park();
		testPark.loadFromStream( bais );
		testPark.compile();
		
		return testPark;
    }


    public void init(GLAutoDrawable drawable)
    {
    	GL gl = drawable.getGL();
        
        gl.glShadeModel(GL.GL_SMOOTH);              // Enable Smooth Shading
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background
        gl.glClearDepth(1.0f);                      // Depth Buffer Setup
        gl.glEnable(GL.GL_DEPTH_TEST);              // Enables Depth Testing
        gl.glDepthFunc(GL.GL_LEQUAL);               // The Type Of Depth Testing To Do
        // Really Nice Perspective Calculations
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);  
        gl.glEnable(GL.GL_TEXTURE_2D);
        
        
        drawable.addKeyListener(this);
        drawable.addMouseListener(this);
        drawable.addMouseMotionListener(this);
        drawable.addMouseWheelListener(this);
        
        loadTextures();
        
        resetViewer();
        
    }
    
    public void setRenderObject(IRenderable obj)
    {
    	m_renderObject = obj;
    }
    
    public void loadTextures()
    {
    	TextureManager texMan = TextureManager.getInstance();
    	
    	String textureBase = "/Users/darkhelmet/workspace/RCTGL/data/textures";
    	String surfaceTextureBase = textureBase + "/surfaces/";
    	
    	texMan.loadTexture(surfaceTextureBase + "water2.bmp", RCTGLTextures.WATER_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "grass4b.tga", RCTGLTextures.GRASS_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "dirt1.tga", RCTGLTextures.DIRT_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "mars1.tga", RCTGLTextures.MARTIAN_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "sand1.tga", RCTGLTextures.SAND_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "icetop1.tga", RCTGLTextures.SNOW_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "gravel1-b.tga", RCTGLTextures.ROCK_SURFACE, true, true);
    	
    	texMan.loadTexture(surfaceTextureBase + "checker1.tga", RCTGLTextures.CHECKERBOARD_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "green1.tga", RCTGLTextures.GREEN_GRID_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "grey1.tga", RCTGLTextures.GREY_ROOF_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "iron1.png", RCTGLTextures.IRON_ROOF_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "jungle1.tga", RCTGLTextures.JUNGLE_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "logroof.png", RCTGLTextures.LOG_ROOF_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "purple1.tga", RCTGLTextures.PURPLE_GRID_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "red1.tga", RCTGLTextures.RED_GRID_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "roofing1.tga", RCTGLTextures.ROOFING_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "sand1.tga", RCTGLTextures.SAND_SURFACE, true, true);
    	texMan.loadTexture(surfaceTextureBase + "yellow1.tga", RCTGLTextures.YELLOW_GRID_SURFACE, true, true);
    	
    	
    	String pathTextureBase = textureBase + "/paths/";   
    	texMan.loadTexture(pathTextureBase + "00-00.tga", RCTGLTextures.BLUE_QUEUE, true, true);
    	texMan.loadTexture(pathTextureBase + "01-00.tga", RCTGLTextures.RED_QUEUE, true, true);
    	texMan.loadTexture(pathTextureBase + "02-00.tga", RCTGLTextures.YELLOW_QUEUE, true, true);
    	texMan.loadTexture(pathTextureBase + "03-00.tga", RCTGLTextures.GREEN_QUEUE, true, true);
    	
    	
    	texMan.loadTexture(pathTextureBase + "04-base.tga", RCTGLTextures.GREY_TARMAC_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "05-base.tga", RCTGLTextures.RED_TARMAC_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "06-base.tga", RCTGLTextures.BROWN_TARMAC_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "07-base.tga", RCTGLTextures.GREEN_TARMAC_PATH, true, true);
    	
    	texMan.loadTexture(pathTextureBase + "0D-base.tga", RCTGLTextures.DIRT_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "0E-base.tga", RCTGLTextures.BLACK_DIRT_PATH, true, true);
    	
    	texMan.loadTexture(pathTextureBase + "0C-base.tga", RCTGLTextures.CRAZY_TILE_PATH, true, true);
    	
    	texMan.loadTexture(pathTextureBase + "08-base.tga", RCTGLTextures.TILE_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "09-base.tga", RCTGLTextures.GREEN_TILE_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "0A-base.tga", RCTGLTextures.RED_TILE_PATH, true, true);
    	texMan.loadTexture(pathTextureBase + "0B-base.tga", RCTGLTextures.GREEN_TILE_PATH, true, true);
    	
    	String edgeTextureBase = textureBase + "/edges/";
    	texMan.loadTexture(edgeTextureBase + "dirtwall.tga", RCTGLTextures.ROCK_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "bricks.tga", RCTGLTextures.BRICK_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "rustwall.tga", RCTGLTextures.IRON_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "wood1.tga", RCTGLTextures.WOOD_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "greywall.tga", RCTGLTextures.GREY_WALL_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "yelwall.tga", RCTGLTextures.YELLOW_WALL_EDGE, true, true);	
    	texMan.loadTexture(edgeTextureBase + "darkwall.tga", RCTGLTextures.BLACK_WALL_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "redwall.tga", RCTGLTextures.RED_WALL_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "icewall.tga", RCTGLTextures.ICE_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "purwall.tga", RCTGLTextures.PURPLE_WALL_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "grnwall.tga", RCTGLTextures.GREEN_WALL_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "brstwall.tga", RCTGLTextures.BROWN_STONE_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "grstwall.tga", RCTGLTextures.GREY_STONE_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "skyawall.tga", RCTGLTextures.SKYSCRAPER_A_EDGE, true, true);
    	texMan.loadTexture(edgeTextureBase + "skybwall.tga", RCTGLTextures.SKYSCRAPER_B_EDGE, true, true);
    	
    	
    	
    	
    	/*
    		 
    		Texture waterTex = texMan.getTexture(RCTGLTextures.WATER);
    		Texture grassTex = texMan.getTexture(RCTGLTextures.GRASS);
    		
    		System.out.println("water=" + waterTex);
    		System.out.println("grass=" + grassTex);
    		
    		System.out.println("waterID=" + waterTex.getTextureObject());
    		System.out.println("grassID=" + grassTex.getTextureObject());
    	*/
    		
    	
    	
    }
    
    

    public void display(GLAutoDrawable drawable)
    {
    	
    	final GL gl = drawable.getGL();
    	
    	
		
		
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();
        
        double [] coords = m_viewer.getPosition();
        double [] rotation = m_viewer.getRotation();
        
        gl.glRotated(rotation[2], 1, 0, 0);
        gl.glRotated(rotation[0], 0, 1, 0);
        gl.glTranslated(coords[0], coords[1], coords[2]);
        
        
        gl.glPushMatrix();
        
        m_renderObject.render(gl);
        
        gl.glPopMatrix();
        
        gl.glFlush();
        
    }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
    {
    	final GL gl = drawable.getGL();

        if (height <= 0) // avoid a divide by zero error!
            height = 1;
        final float h = (float) width / (float) height;
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        m_glu.gluPerspective(45.0f, h, 0.1f, 5000.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged)
    {
    }
    
    public void resetViewer()
    {
    	m_viewer.moveAbsolute(0, 0, 0);
    	m_viewer.rotateAbsolute(0, 0, 0);
    }

	public void keyPressed(KeyEvent e)
	{
		//System.out.println("got key pressed " + e.toString());
		
		switch(e.getKeyCode())
		{
		case KeyEvent.VK_ESCAPE:
			System.exit(0);
		case KeyEvent.VK_F2:
			try
			{
				SV4Park newPark = selectParkFromDisk();
				if(newPark != null)
				{
					setRenderObject( newPark.getScene() );
					resetViewer();
				}
			}
			catch(Exception exc)
			{
				
			}
			
		case KeyEvent.VK_W:
			m_viewer.moveRelative(0, 0, RCTGLViewer.MOVEUNIT);
			break;
		case KeyEvent.VK_S:
			m_viewer.moveRelative(0, 0, -RCTGLViewer.MOVEUNIT);
			break;
		case KeyEvent.VK_D:
			m_viewer.moveRelative(-RCTGLViewer.MOVEUNIT, 0, 0);
			break;
		case KeyEvent.VK_A:
			m_viewer.moveRelative(RCTGLViewer.MOVEUNIT, 0, 0);
			break;
		case KeyEvent.VK_PAGE_UP:
			m_viewer.moveRelative(0, -RCTGLViewer.MOVEUNIT, 0);
			break;
		case KeyEvent.VK_PAGE_DOWN:
			m_viewer.moveRelative(0, RCTGLViewer.MOVEUNIT, 0);
			break;
		}
		
		
		
	}

	public void keyReleased(KeyEvent e)
	{
		//System.out.println("got key released " + e.toString());
		
		
		
	}

	public void keyTyped(KeyEvent e)
	{
		//System.out.println("got key typed " + e.toString());
		
		
		
	}

	public void mouseWheelMoved(MouseWheelEvent e)
	{
		
	}

	public void mouseDragged(MouseEvent e)
	{
		System.out.println("mouseDragged(" + e.toString() + ")");
		
		Point p = e.getPoint();
		
		m_viewer.rotateRelative(p.x - m_lastMouseCoords.getX(), 0, p.y - m_lastMouseCoords.getY());
		
		m_lastMouseCoords.setPos(p.x, p.y);
		
	}

	public void mouseMoved(MouseEvent e)
	{
		
	}

	public void mouseClicked(MouseEvent e)
	{
		System.out.println("mouseClicked(" + e.toString() + ")");
		
	}

	public void mouseEntered(MouseEvent e)
	{
		
	}

	public void mouseExited(MouseEvent e)
	{
		
	}

	public void mousePressed(MouseEvent e)
	{
		System.out.println("mousePressed(" + e.toString() + ")");
		
		m_lastMouseCoords = new PanoVertex2( e.getPoint().x, e.getPoint().y );
		
	}

	public void mouseReleased(MouseEvent e)
	{
		System.out.println("mouseReleased(" + e.toString() + ")");
		
		m_lastMouseCoords = null;
		
		
	}
	
	
	
    

}
